package com.dev.security.login.service;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.dev.security.login.beans.LoginData;
import com.dev.security.login.beans.LoginSource;
import com.dev.security.login.beans.LoginUser;
import com.dev.security.login.util.CookieEncrypt;
import com.dev.security.login.util.LoginConstants;

/**
 * 登录管理类
 * @author <b>DEVILIVED</b>
 * <br/>E-Mail：3375758@qq.com
 * <br/>创建时间： 2014年6月28日 下午10:30:31 
 * @version V1.0
 */
public class LoginManager {
	
	private Logger log = LogManager.getLogger(LoginManager.class);
	
	/**
	 * 是否使用cookie
	 */
	private boolean cookie;
	
	/**
	 * cookie有效时间，默认1800秒
	 */
	private int cookieMaxAge = 1800;
	
	/**
	 * cookie有效域名，默认null，例如：.baidu.cn
	 */
	private String cookieDomain;
	
	/**
	 * cookie的pash，默认为"/"
	 */
	private String cookiePath = "/";
	
	/**
	 * 账号字段名，默认为account
	 */
	private String accountFieldName = "account";
	
	/**
	 * 密码字段名，默认为password
	 */
	private String passwordFieldName = "password";
	
	/**
	 * 是否保存cookie
	 */
	private String isCookieFieldName = "isCookie";
	
	/**
	 * session、cookie：存储用户user_id地址, request：存储用户信息地址，默认_MEMORY_LOGIN_DATA
	 */
	private String memoryName = "_MEMORY_LOGIN_DATA";
	
	/**
	 * cookie存储时：加密key，默认123456789
	 */
	private String cookieEncryptKey = "123456789";
	
	/**
	 * 单点登录接口
	 */
	private LoginSSOFilter loginSSOFilter;

	/**
	 * 权限过滤接口
	 */
	private List<ValidateFilter> validateFilters = new ArrayList<ValidateFilter>();
	
	/**
	 * 密码加密接口
	 */
	private PasswordEncoder passwordEncoder;
	
	/**
	 * 用户接口
	 */
	private UserService userService;
	
	/**
	 * @Description: 校验是否可以访问
	 * @param request 请求
	 * @param response 响应
	 * @param uri 访问地址
	 * @return 返回校验结果代码
	 */
	public int validate(HttpServletRequest request, HttpServletResponse response, String uri) {
		LoginSource source = this.userService.findLoginSource(uri);
		if(source == null) {
			return LoginConstants.VALIDATE_TRANSIT;
		}
		return new ValidateInvocation(
				this.getValidateFilters().iterator(), 
				request, 
				this.getLoginUser(request, response), 
				source).invoke();
	}
	
	/**
	 * @Description: 校验是否可以访问（简化）
	 * @param request 请求
	 * @param response 响应
	 * @param uri 访问地址
	 * @return 是否通过校验：通过、true，未通过、false
	 */
	public boolean validateSimple(HttpServletRequest request,  HttpServletResponse response, String uri) {
		return this.validate(request, response, uri) == LoginConstants.VALIDATE_TRANSIT;
	}
	
	/**
	 * 
	 * @Description: 登录
	 * @param request 请求
	 * @param response 相应
	 * @return code:参考LoginConstants.LOGIN_；loginUser:登录信息，失败返回null
	 */
	public LoginData login(HttpServletRequest request, HttpServletResponse response) {
		String user_account = request.getParameter(this.getAccountFieldName());
		String user_password = request.getParameter(this.getPasswordFieldName());
		LoginUser user = this.userService.findLoginUser(user_account, "1");
		if(user == null) {
			request.setAttribute("account", user_account);
			return new LoginData(LoginConstants.LOGIN_INVALID, user);
		}
		if(!this.passwordEncoder.matches(user_password, user.getUserPassword())) {
			request.setAttribute("account", user_account);
			return new LoginData(LoginConstants.LOGIN_PASSWORD, user);
		}
		//保存user_id
		this.saveMemeryUserId(request, response, user.getUserId());
		String code = request.getParameter(this.getIsCookieFieldName());
		if(StringUtils.equals("1", code)) {
			this.saveCookieUserId(request, response, user.getUserId());
		}
		//当前请求保存user信息，可以减少查询次数
		request.setAttribute(this.getMemoryName(), user);
		return new LoginData(LoginConstants.LOGIN_TRANSIT, user);
	}
	
	/**
	 * 
	 * @Description: 获得登录信息
	 * @param request 请求
	 * @return 登录信息
	 */
	public LoginUser getLoginUser(HttpServletRequest request, HttpServletResponse response) {
		LoginUser user = (LoginUser) request.getAttribute(this.getMemoryName());
		if(user == null) {
			String user_id = (String) request.getSession().getAttribute(this.getMemoryName());
			if(StringUtils.isEmpty(user_id)) {
				if(this.isCookie()) {
					Cookie[] cookies = request.getCookies();
					if(cookies != null) {
						for(Cookie cookie:cookies) {
							if(StringUtils.equals(this.getMemoryName(), cookie.getName())) {
								try {
									user_id = CookieEncrypt.aesDecrypt(cookie.getValue(), this.getCookieEncryptKey());
								} catch (Exception e) {
									log.error("cookie解密错误！", e);
								}
								break;
							}
						}
					}
				}
				if(this.loginSSOFilter != null && StringUtils.isEmpty(user_id)) {
					user_id = this.loginSSOFilter.login(request);
					if(!StringUtils.isEmpty(user_id)) {
						this.saveMemeryUserId(request, response, user_id);
						this.saveCookieUserId(request, response, user_id);
					}
				}
			}
			if(!StringUtils.isEmpty(user_id)) {
				user = this.userService.findLoginUser(user_id);
				request.setAttribute(this.getMemoryName(), user);
			}
		}
		return user;
	}
	/**
	 * 保存user_id到session、cookie
	 * @param request
	 * @param response
	 * @param user_id
	 * @return user_id
	 */
	public String saveMemeryUserId(HttpServletRequest request, HttpServletResponse response, String user_id) {
		request.getSession().setAttribute(this.getMemoryName(), user_id);
		return user_id;
	}

	/**
	 * 存入cookie
	 * @author 潜行的青衣
	 * @version
	 * @param request
	 * @param response
	 * @param user_id
	 * @return
	 */
	public String saveCookieUserId(HttpServletRequest request, HttpServletResponse response, String user_id) {
		if(this.isCookie()) {
			try {
				String encrypt = CookieEncrypt.aesEncrypt(user_id, this.getCookieEncryptKey());
				Cookie cookie = new Cookie(this.getMemoryName(), encrypt);
				cookie.setPath(this.getCookiePath());
				if(!StringUtils.isEmpty(this.getCookieDomain())) {
					cookie.setDomain(this.getCookieDomain());
				}
				cookie.setMaxAge(this.getCookieMaxAge());
				response.addCookie(cookie);
			} catch (Exception e) {
				log.error("cookie 加密错误！", e);
			}
		}
		return user_id;
	}
	/**
	 * 退出登录，删除登录信息
	 * @param request
	 * @param response
	 */
	public void logout(HttpServletRequest request, HttpServletResponse response) {
		//清除request
		request.removeAttribute(this.getMemoryName());
		//清空session
		request.getSession().removeAttribute(this.getMemoryName());
		//删除cookie
		if(this.isCookie()) {
			Cookie cookie = new Cookie(this.getMemoryName(), null);
			cookie.setPath(this.getCookiePath());
			if(!StringUtils.isEmpty(this.getCookieDomain())) {
				cookie.setDomain(this.getCookieDomain());
			}
			cookie.setMaxAge(getCookieMaxAge());
			response.addCookie(cookie);
		}
		//sso登出
		if(this.loginSSOFilter != null) {
			this.loginSSOFilter.logout(request, response);
		}
	}

	public boolean isCookie() {
		return cookie;
	}

	public void setCookie(boolean cookie) {
		this.cookie = cookie;
	}

	public String getAccountFieldName() {
		return accountFieldName;
	}

	public void setAccountFieldName(String accountFieldName) {
		this.accountFieldName = accountFieldName;
	}

	public String getPasswordFieldName() {
		return passwordFieldName;
	}

	public void setPasswordFieldName(String passwordFieldName) {
		this.passwordFieldName = passwordFieldName;
	}

	public String getMemoryName() {
		return memoryName;
	}

	public void setMemoryName(String memoryName) {
		this.memoryName = memoryName;
	}

	public LoginSSOFilter getLoginSSOFilter() {
		return loginSSOFilter;
	}

	public void setLoginSSOFilter(LoginSSOFilter loginSSOFilter) {
		this.loginSSOFilter = loginSSOFilter;
	}

	public int getCookieMaxAge() {
		return cookieMaxAge;
	}

	public void setCookieMaxAge(int cookieMaxAge) {
		this.cookieMaxAge = cookieMaxAge;
	}

	public String getCookieDomain() {
		return cookieDomain;
	}

	public void setCookieDomain(String cookieDomain) {
		this.cookieDomain = StringUtils.trimToEmpty(cookieDomain);
	}

	public List<ValidateFilter> getValidateFilters() {
		return validateFilters;
	}

	public void setValidateFilters(List<ValidateFilter> validateFilters) {
		this.validateFilters.addAll(validateFilters);
	}

	public PasswordEncoder getPasswordEncoder() {
		return passwordEncoder;
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	public String getCookiePath() {
		return cookiePath;
	}

	public void setCookiePath(String cookiePath) {
		this.cookiePath = cookiePath;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}
	
	public String getIsCookieFieldName() {
		return isCookieFieldName;
	}

	public void setIsCookieFieldName(String isCookieFieldName) {
		this.isCookieFieldName = isCookieFieldName;
	}

	public String getCookieEncryptKey() {
		return cookieEncryptKey;
	}

	public void setCookieEncryptKey(String cookieEncryptKey) {
		this.cookieEncryptKey = cookieEncryptKey;
	}
}
